package qc.module.platform.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import qc.common.core.enums.QcUserPwdSrcTypeEnum;
import qc.common.core.enums.ResourceStatusFlagEnum;
import qc.common.core.exception.QCPromptException;
import qc.common.core.tree.QCTreeNode;
import qc.common.core.tree.TreeDataDto;
import qc.common.core.unify.QCUnifyReturnValue;
import qc.common.core.utils.DateUtil;
import qc.common.core.utils.PasswordUtil;
import qc.module.platform.dto.dept.DeptQueryConditionDto;
import qc.module.platform.dto.dept.DeptSimpleDto;
import qc.module.platform.dto.project.ProjectDto;
import qc.module.platform.dto.user.*;
import qc.module.platform.entity.*;
import qc.module.platform.mapper.UserMapper;
import qc.module.platform.repository.QcUsersRepository;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * UserService
 *
 * @author QuCheng Tech
 * @create 2023/1/11
 */
@Service
public class UserService {

    private QcUsersRepository repository;
    private DeptService deptService;
    private DeptUserService deptUserService;
    private ProjectService projectService;
    private UserProjectService userProjectService;
    private RoleUserService roleUserService;
    private QcUserPasswordLogService passwordLogService;

    @Autowired
    public void setQcUsersRepository(QcUsersRepository repository) {
        this.repository = repository;
    }

    @Autowired
    public void setProjectService(ProjectService projectService) {
        this.projectService = projectService;
    }

    @Autowired
    public void setUserProjectService(UserProjectService userProjectService) {
        this.userProjectService = userProjectService;
    }

    @Autowired
    public void setDeptService(DeptService deptService) {
        this.deptService = deptService;
    }

    @Autowired
    public void setDeptUserService(DeptUserService deptUserService) {
        this.deptUserService = deptUserService;
    }

    @Autowired
    public void setRoleUserService(RoleUserService roleUserService) {
        this.roleUserService = roleUserService;
    }

    @Autowired
    public void setQcUserPasswordLogService(QcUserPasswordLogService passwordLogService) {
        this.passwordLogService = passwordLogService;
    }

    /**
     * 根据登录用户名或手机号获取用户信息，用于登录时获取存在的用户信息，不对用户状态进行判断
     *
     * @param codeOrPhone 登录用户名或手机号
     * @return qc.module.platform.entity.QcUsers
     * @author QuCheng Tech
     * @date 2023/1/11
     */
    public QcUsers getUserByCodeOrPhone(String codeOrPhone) {
        //如输入的用户名或手机号为空，返回null
        if (StringUtils.isBlank(codeOrPhone)) return null;

        LambdaQueryWrapper<QcUsers> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(QcUsers::getCode, codeOrPhone).or().eq(QcUsers::getPhone, codeOrPhone);

        QcUsers qcUser = repository.selectOne(wrapper);

        return qcUser;
    }

    /**
     * 根据手机号获取用户信息，用于登录时获取存在的用户信息，不对用户状态进行判断
     *
     * @param phone 手机号
     * @return qc.module.platform.entity.QcUsers
     * @author QuCheng Tech
     * @date 2024/9/24
     */
    public QcUsers getUserByPhone(String phone) {
        //如输入的手机号为空，返回null
        if (StringUtils.isBlank(phone)) return null;

        LambdaQueryWrapper<QcUsers> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(QcUsers::getPhone, phone);

        QcUsers qcUser = repository.selectOne(wrapper);

        return qcUser;
    }

    /**
     * 根据指定ID获取用户信息
     *
     * @param userId: 查询的用户ID
     * @return QcUsers 返回用户详细信息
     * @author QcCheng Tech
     * @date 2023/7/5
     */
    public QcUsers getEntity(int userId) {
        LambdaQueryWrapper<QcUsers> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(QcUsers::getId, userId);

        return repository.selectOne(wrapper);
    }

    /**
     * 判断用户状态，根据条件查询用户，关键字可以是姓名，昵称，手机号，微信号，没有则查询全部
     *
     * @param dto:  查询用户时的查询条件
     * @param flag: 查询时是否判断用户状态
     * @return 用户信息结合
     * @author QcCheng Tech
     * @date 2023/7/5
     */
    public List<UserInfoDto> queryPlatformUser(UserQueryConditionDto dto, ResourceStatusFlagEnum flag) {
        LambdaQueryWrapper<QcUsers> wrapper = new LambdaQueryWrapper<>();
        if (flag != null)
            wrapper.eq(QcUsers::getFlag, flag);
        //传入参数对象不为空，根据条件查询，为空，则查询全部
        if (dto != null) {
            if (!StringUtils.isBlank(dto.getWords())) {
                //关键字，模糊匹配用户登录名、手机号、微信ID，精确匹配用户ID
                wrapper.like(QcUsers::getName, dto.getWords())
                        .or().like(QcUsers::getCode, dto.getWords())
                        .or().like(QcUsers::getPhone, dto.getWords())
                        .or().like(QcUsers::getWeixinid, dto.getWords())
                        .or().eq(QcUsers::getId, dto.getWords());
            }
            //如果不包含已删除用户，根据用户状态进行过滤
            if (dto.isIncludedelete() == false)
                wrapper.ne(QcUsers::getFlag, ResourceStatusFlagEnum.DELETED);
        }

        //排序，先按排序号升序，再按名称升序
        wrapper.orderByAsc(QcUsers::getOdr).orderByAsc(QcUsers::getName);

        List<QcUsers> qcUsersList = repository.selectList(wrapper);
        if (qcUsersList != null && !qcUsersList.isEmpty()) {
            return UserMapper.MAPPER.toDtoList(qcUsersList);
        }
        return null;
    }

    /**
     * 根据关键字查询，关键字可以是名称、登录用户名、手机号、微信id，没有则查询全部
     *
     * @param dto UserQueryConditionDto
     * @return 简要用户信息集合
     * @author QcCheng Tech
     * @since 2023/2/8
     */
    public List<UserSimpleInfoDto> queryPlatformUserSimple(UserQueryConditionDto dto, ResourceStatusFlagEnum flag) {
        List<UserInfoDto> userInfoDtoList = queryPlatformUser(dto, flag);
        if (userInfoDtoList != null && !userInfoDtoList.isEmpty()) {
            return UserMapper.MAPPER.toInfoDtoSimpleList(userInfoDtoList);
        }
        return null;
    }

    /**
     * 根据关键字查询，关键字可以是名称、登录用户名、手机号、微信id，没有则查询全部
     *
     * @param dto UserQueryConditionDto
     * @return 用户信息集合
     * @author QcCheng Tech
     * @since 2023/2/8
     */
    public List<UserInfoDto> queryProjectUsers(UserQueryConditionDto dto) throws QCPromptException {
        if (StringUtils.isBlank(dto.getProject()))
            throw new QCPromptException("必须指定项目编码");
        List<QcUsers> qcUsers = queryProjectUsersList(dto);
        if (qcUsers.size() > 0x0) return UserMapper.MAPPER.toInfoDtoList(qcUsers);
        return null;
    }

    /**
     * 根据关键字查询，关键字可以是名称、登录用户名、手机号、微信id，没有则查询全部
     *
     * @param dto UserQueryConditionDto
     * @return 简要用户信息集合
     * @author QcCheng Tech
     * @since 2023/2/8
     */
    public List<UserSimpleInfoDto> queryProjectUserSimple(UserQueryConditionDto dto) throws QCPromptException {
        if (StringUtils.isBlank(dto.getProject()))
            throw new QCPromptException("必须指定项目编码");
        List<QcUsers> qcUsers = queryProjectUsersList(dto);
        if (qcUsers != null && !qcUsers.isEmpty()) {
            return UserMapper.MAPPER.toSimpDtoLists(qcUsers);
        }
        return null;
    }

    /**
     * 查询项目用户，可以根据用户ID，姓名，微信号，手机号对项目用户进行模糊查询，
     *
     * @param dto: 查询条件
     * @return List<QcUsers> 返回用户信息
     * @author QcCheng Tech
     * @date 2023/7/5
     */
    public List<QcUsers> queryProjectUsersList(UserQueryConditionDto dto) {
        MPJLambdaWrapper<QcUsers> wrapper = new MPJLambdaWrapper<QcUsers>().selectAll(QcUsers.class);//查询字段
        //判断有无模糊条件 无则查询项目用户
        if (!StringUtils.isBlank(dto.getWords())) {
            wrapper.innerJoin(QcUserProject.class, QcUserProject::getUserid, QcUsers::getId).eq(QcUserProject::getProjectcode, dto.getProject())
                    //关键字，模糊匹配用户登录名、手机号、微信ID，精确匹配用户ID
                    .like(QcUsers::getName, dto.getWords())
                    .or().like(QcUsers::getCode, dto.getWords())
                    .or().like(QcUsers::getPhone, dto.getWords())
                    .or().like(QcUsers::getWeixinid, dto.getWords())
                    .or().eq(QcUsers::getId, dto.getWords());
        } else {
            wrapper.innerJoin(QcUserProject.class, QcUserProject::getUserid, QcUsers::getId).eq(QcUserProject::getProjectcode, dto.getProject());
        }
        //如果有部门id，根据部门id查询用户
        if (!StringUtils.isBlank(dto.getDept())) {
            wrapper.innerJoin(QcDeptUser.class, QcDeptUser::getUserid, QcUsers::getId).eq(QcDeptUser::getDeptid, dto.getDept());
        }
        //如果不包含已删除用户，根据用户状态进行过滤
        if (dto.isIncludedelete() == false)
            wrapper.ne(QcUsers::getFlag, ResourceStatusFlagEnum.DELETED);

        //排序，先按排序号升序，再按名称升序
        wrapper.orderByAsc(QcUsers::getOdr).orderByAsc(QcUsers::getName);

        return repository.selectJoinList(QcUsers.class, wrapper);
    }

    /**
     * 新增用户，根据添加信息中判断平台用户或是项目用户，有项目编号则为项目用户
     *
     * @param dto: 添加的用户信息
     * @return String 成功返回null
     * @author QcCheng Tech
     * @date 2023/7/5
     */
    public String add(UserAddDto dto) throws QCPromptException {
        if (dto == null)
            return QCUnifyReturnValue.Warn("对象不能为空");
        if (StringUtils.isBlank(dto.getName()))
            return QCUnifyReturnValue.Warn("用户名称不能为空");
        //用户的登录编码或手机必须有1个，否则无法进行登录
        if (StringUtils.isBlank(dto.getCode()) && StringUtils.isBlank(dto.getPhone()))
            return QCUnifyReturnValue.Warn("用户登录名和手机号必须至少有一个");

        //判断是否存在相同的登录名或手机号的用户
        QcUsers existUser = getExistUserByCodeOrPhone(dto.getCode(), dto.getPhone(), 0x0);
        if (existUser != null) {
            //判断用户状态是否为删除，删除时需要提示由平台管理员进行操作
            if (existUser.getFlag() == ResourceStatusFlagEnum.DELETED)
                return QCUnifyReturnValue.Warn("平台中已存在被删除的用户名或手机号，请联系平台管理员进行处理。");
            //判断时登录名重复还是手机号重复
            if (!StringUtils.isBlank(dto.getCode()) && StringUtils.equalsIgnoreCase(dto.getCode(), existUser.getCode()) == true)
                return QCUnifyReturnValue.Warn("用户登录名已存在，用户登录名不能相同");
            if (!StringUtils.isBlank(dto.getPhone()) && StringUtils.equalsIgnoreCase(dto.getPhone(), existUser.getPhone()) == true)
                return QCUnifyReturnValue.Warn("手机号已存在，手机号不能相同");
        }
        //判断增加项目用户时，项目是否存在
        if (!StringUtils.isBlank(dto.getProject())) {
            if (!projectService.hasCodeExist(dto.getProject()))
                return QCUnifyReturnValue.Warn("指定项目不存在！");
        }

        //DTO转换为Entity
        QcUsers en = UserMapper.MAPPER.UserAddDtoToEntity(dto);

        //新增时需设置ID
        Integer newId = generateId();
        en.setId(newId);

        //新增用户时密码使用默认
        en.setPassword(PasswordUtil.getDefaultQuChengEncryptPassword());
        //设置密码信息
        en.setPwdflag(QcUserPwdSrcTypeEnum.INIT);
        en.setPwdtm(DateUtil.getNowDate());

        Date expiretime;
        if (!StringUtils.isBlank(dto.getExpiretime())) {
            try {
                // 解析过期时间
                expiretime = DateUtil.parseDate(dto.getExpiretime());
                //时间精确到日
                expiretime = DateUtil.parseDate(DateUtil.getDateString(expiretime));
                en.setExpiredtm(expiretime);
            } catch (Exception e) {
                // 抛出自定义异常，开始时间转换错误
                throw new QCPromptException("开始时间转换错误");
            }
        }

        if (repository.insert(en) < 0x1)
            return QCUnifyReturnValue.Warn("新增用户失败");

        //判断是否为项目用户，是则添加用户与项目关系
        if (!StringUtils.isBlank(dto.getProject())) {
            userProjectService.add(newId, dto.getProject());
        }

        //如果有部门设置用户与部门关联关系
        if (dto.getDepts() != null && dto.getDepts().size() > 0x0) {
            UserDeptSetDto userDeptSetDto = new UserDeptSetDto();
            userDeptSetDto.setUserid(newId);
            userDeptSetDto.setProject(dto.getProject());
            userDeptSetDto.setDids(dto.getDepts());
            setUserDepts(userDeptSetDto);
        }

        return QCUnifyReturnValue.Success();
    }

    /**
     * 修改用户信息
     *
     * @param dto: 需要修改的属性
     * @return String 成功返回null，失败返回错误信息
     * @author QcCheng Tech
     * @date 2023/7/5
     */
    public String update(UserEditDto dto) throws QCPromptException {
        if (dto == null)
            return QCUnifyReturnValue.Warn("对象不能为空");
        if (dto.getId() < 0x1)
            return QCUnifyReturnValue.Warn("用户ID不能为空");
        if (StringUtils.isBlank(dto.getName()))
            return QCUnifyReturnValue.Warn("用户名称不能为空");
        //根据用户ID获取已经存在的用户信息，判断用户是否存在，后面更新时需要将用户自定义信息赋值给更新的Entity
        QcUsers existEntity = getEntity(dto.getId());
        //判断修改的用户信息是否存在
        if (existEntity == null)
            return QCUnifyReturnValue.Warn("修改指定的用户ID不存在");

        //用户的登录编码或手机必须有1个，否则无法进行登录
        if (StringUtils.isBlank(dto.getCode()) && StringUtils.isBlank(dto.getPhone()))
            return QCUnifyReturnValue.Warn("用户登录名和手机号必须至少有一个");

        //判断是否存在相同的登录名或手机号的用户
        QcUsers existUser = getExistUserByCodeOrPhone(dto.getCode(), dto.getPhone(), dto.getId());
        if (existUser != null) {
            //判断用户状态是否为删除，删除时需要提示由平台管理员进行操作
            if (existUser.getFlag() == ResourceStatusFlagEnum.DELETED)
                return QCUnifyReturnValue.Warn("平台中已存在被删除的用户名或手机号，请联系平台管理员进行处理。");
            //判断时登录名重复还是手机号重复
            if (!StringUtils.isBlank(dto.getCode()) && StringUtils.equalsIgnoreCase(dto.getCode(), existUser.getCode()) == true)
                return QCUnifyReturnValue.Warn("用户登录名已存在，用户登录名不能相同");
            if (!StringUtils.isBlank(dto.getPhone()) && StringUtils.equalsIgnoreCase(dto.getPhone(), existUser.getPhone()) == true)
                return QCUnifyReturnValue.Warn("手机号已存在，手机号不能相同");
        }

        //如果有部门设置用户与部门关联关系
        if (dto.getDepts() != null && dto.getDepts().size() > 0x0) {
            UserDeptSetDto userDeptSetDto = new UserDeptSetDto();
            userDeptSetDto.setUserid(dto.getId());
            userDeptSetDto.setProject(dto.getProject());
            userDeptSetDto.setDids(dto.getDepts());
            setUserDepts(userDeptSetDto);
        }else {
            //如果部门为空，删除用户与当前项目部门关联关系
            deleteUserDepts(dto.getProject(),dto.getId());
        }
        //DTO转换为Entity
        QcUsers en = UserMapper.MAPPER.UserEditDtoToEntity(dto);

        Date expiretime;
        if (!StringUtils.isBlank(dto.getExpiretime())) {
            try {
                // 解析过期时间
                expiretime = DateUtil.parseDate(dto.getExpiretime());
                //时间精确到日
                expiretime = DateUtil.parseDate(DateUtil.getDateString(expiretime));
                en.setExpiredtm(expiretime);
            } catch (Exception e) {
                // 抛出自定义异常，开始时间转换错误
                throw new QCPromptException("开始时间转换错误");
            }
        }

        //将已有的Entity中的用户自定义信息赋值给修改的Entity，否则会导致修改后自定义信息为空
        if (StringUtils.isNotBlank(existEntity.getCustominfo()))
            en.setCustominfo(existEntity.getCustominfo());

        //执行修改
        if (repository.updateById(en) < 0x1)
            return QCUnifyReturnValue.Warn("修改失败");

        return QCUnifyReturnValue.Success();
    }

    /**
     * 根据ID删除用户,逻辑删除更改用户状态
     * <p>
     * 删除平台用户时需要同时删除用户与项目的关联信息
     *
     * @param userId:        用户ID
     * @param isLogicDelete: 是否为逻辑删除
     * @return String  成功返回null，失败返回错误信息
     * @author QcCheng Tech
     * @date 2023/7/5
     */
    public String delete(int userId, boolean isLogicDelete) {
        if (!hasIdExist(userId))
            return QCUnifyReturnValue.Warn("删除的用户ID不存在");

        if (isLogicDelete) {
            //逻辑删除，只修改用户状态标记
            LambdaUpdateWrapper<QcUsers> wrapper = new LambdaUpdateWrapper<>();
            wrapper.eq(QcUsers::getId, userId);
            wrapper.set(QcUsers::getFlag, ResourceStatusFlagEnum.DELETED);
            repository.update(null, wrapper);
        } else {
            //物理删除，需要删除所有信息，包含关联关系
            //关联关系：用户--部门，用户--角色，用户--项目
            userProjectService.deleteByUserId(userId);
            deptUserService.deleteByUserId(userId);
            roleUserService.deleteByUserId(userId);

            repository.deleteById(userId);
        }
        return QCUnifyReturnValue.Success();
    }

    /***
     * 恢复已删除的指定用户
     *
     * @param userId 用户ID
     * @return java.lang.String
     * @author QuCheng Tech
     * @since 2025/1/17
     */
    public String restore(int userId) {
        QcUsers en = getEntity(userId);
        if (en == null)
            return QCUnifyReturnValue.Warn("要恢复的用户信息不存在");
        //判断状态
        if (en.getFlag() != ResourceStatusFlagEnum.DELETED)
            return QCUnifyReturnValue.Warn("要恢复的用户状态错误，不是已删除状态");

        //修改用户状态为正常
        LambdaUpdateWrapper<QcUsers> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(QcUsers::getId, userId);
        wrapper.set(QcUsers::getFlag, ResourceStatusFlagEnum.NORMAL);
        repository.update(null, wrapper);

        return QCUnifyReturnValue.Success();
    }

    /**
     * 根据用户id与项目编号删除项目用户
     *
     * @param userId:        用户ID
     * @param projectCode:   项目编码
     * @param isLogicDelete: 是否为逻辑删除
     * @return String 删除成功返回null,删除失败返回错误信息
     * @author QcCheng Tech
     * @date 2023/7/5
     */
    public String deleteProjectUser(int userId, String projectCode, boolean isLogicDelete) {
        if (!hasIdExist(userId))
            return QCUnifyReturnValue.Warn("删除的用户ID不存在");
        if (!projectService.hasCodeExist(projectCode))
            return QCUnifyReturnValue.Warn("指定的项目编码不存在");

        //在指定的项目中删除用户，需要先确定用户是否在其他项目中；
        //如果用户只在当前项目中可以进行与用户有关的操作（包含部门、角色关联），如果用户还在其他项目中则只能对当前项目中的信息进行操作
        //获取用户与项目的关联关系
        List<String> userProjectCodes = userProjectService.getByUserId(userId);
        if (userProjectCodes == null || userProjectCodes.size() < 0x1)
            return QCUnifyReturnValue.Warn("指定用户ID不在任何项目中");
        if (!userProjectCodes.contains(projectCode))
            return QCUnifyReturnValue.Warn("用户不在当前项目中");

        boolean userHasOtherProjects = userProjectCodes.size() > 0x1;
        if (userHasOtherProjects) {
            //用户还与其他项目关联，不能修改用户状态或删除用户，否则导致用户在其他项目中无法正常登录和操作
            //不管是否为逻辑删除，均需要删除用户与项目的关联关系
            userProjectService.deleteByUserId(userId);
            //如果是物理删除，获取当前项目中的部门、角色；根据用户ID和关联对象ID进行删除
            if (isLogicDelete) {
                //逻辑删除，不能对用户状态进行修改
            } else {
                //物理删除，需要删除所有信息，包含关联关系
                //关联关系：用户--部门，用户--角色
                List<QcDepts> userDepts = deptService.getUserDepts(projectCode, userId, false);
                if (userDepts != null && userDepts.size() > 0x0) {
                    deptUserService.deleteByDeptIds(userDepts.stream().map(p -> p.getId()).collect(Collectors.toList()));
                }
                //UserService中不能调用RoleService，已经在RoleService中调用UserService中的方法
                //List<QcRoles> userRoles = roleService.getUserRoles(projectCode, userId, false);
                //if (userRoles != null && userRoles.size() > 0x0) {
                //    roleUserService.deleteByRoleIds(userRoles.stream().map(p -> p.getId()).collect(Collectors.toList()));
                //}
            }
        } else {
            //用户只在当前项目中，可以按照平台用户的删除操作进行
            return delete(userId, isLogicDelete);
        }

        return QCUnifyReturnValue.Success();
    }

    /***
     * 禁用指定用户
     *
     * @param userId 用户ID
     * @return java.lang.String
     * @author QuCheng Tech
     * @since 2023/9/1
     */
    public String disable(int userId) {
        QcUsers en = getEntity(userId);
        if (en == null)
            return QCUnifyReturnValue.Warn("指定的用户ID不存在");

        if (en.getFlag() == ResourceStatusFlagEnum.NORMAL) {
            //状态为启用的才可以禁用
            LambdaUpdateWrapper<QcUsers> wrapper = new LambdaUpdateWrapper<>();
            wrapper.eq(QcUsers::getId, userId);
            wrapper.set(QcUsers::getFlag, ResourceStatusFlagEnum.DISABLE);
            repository.update(null, wrapper);
        } else if (en.getFlag() == ResourceStatusFlagEnum.DISABLE) {
            //状态为禁用的不需要进行任何操作
        } else {
            //如果是其他状态，不允许进行操作
            return QCUnifyReturnValue.Warn("指定的用户状态不允许进行禁用操作");
        }

        return QCUnifyReturnValue.Success();
    }

    /***
     * 启用指定用户
     *
     * @param userId 用户ID
     * @return java.lang.String
     * @author QuCheng Tech
     * @since 2023/9/1
     */
    public String enable(int userId) {
        QcUsers en = getEntity(userId);
        if (en == null)
            return QCUnifyReturnValue.Warn("指定的用户ID不存在");

        if (en.getFlag() == ResourceStatusFlagEnum.DISABLE) {
            //状态为禁用的才可以启用
            LambdaUpdateWrapper<QcUsers> wrapper = new LambdaUpdateWrapper<>();
            wrapper.eq(QcUsers::getId, userId);
            wrapper.set(QcUsers::getFlag, ResourceStatusFlagEnum.NORMAL);
            repository.update(null, wrapper);
        } else if (en.getFlag() == ResourceStatusFlagEnum.NORMAL) {
            //状态为禁用的才可以启用，已经是正常状态的不需要进行任何操作
        } else {
            //如果是其他状态，不允许进行操作
            return QCUnifyReturnValue.Warn("指定的用户状态不允许进行启用操作");
        }

        return QCUnifyReturnValue.Success();
    }

    /**
     * 判断指定用户id是否存在
     *
     * @param id: 需要查询的用户ID
     * @return boolean 存在返回true,不存在返回false
     * @author QcCheng Tech
     * @date 2023/7/5
     */
    public boolean hasIdExist(int id) {
        LambdaQueryWrapper<QcUsers> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(QcUsers::getId);
        wrapper.eq(QcUsers::getId, id);

        QcUsers en = repository.selectOne(wrapper);
        if (en != null)
            return true;

        return false;
    }

    /***
     * 根据用户登录名或手机号获取已经存在的用户信息，用于新增或修改用户时判断信息是否重复
     *
     * @param code 用户登录名，可以为空
     * @param phone 手机号，可以为空
     * @param id 排除在外的用户ID，修改时的用户ID
     * @return qc.module.platform.entity.QcUsers
     * @author QuCheng Tech
     * @since 2025/1/17
     */
    QcUsers getExistUserByCodeOrPhone(String code, String phone, int id) {
        //验证是否已存在相同的用户条件： id<>?id and (code=?code or phone=?phone)
        LambdaQueryWrapper<QcUsers> wrapper = new LambdaQueryWrapper<>();
        wrapper.ne(QcUsers::getId, id);
        if (StringUtils.isNotBlank(code)) {
            if (StringUtils.isNotBlank(phone)) {
                wrapper.and(q -> q.eq(QcUsers::getCode, code).or().eq(QcUsers::getPhone, phone));
            } else {
                wrapper.eq(QcUsers::getCode, code);
            }
        } else if (StringUtils.isNotBlank(phone)) {
            wrapper.eq(QcUsers::getPhone, phone);
        }

        QcUsers qcUser = repository.selectOne(wrapper);

        return qcUser;
    }

    /**
     * 获取指定用户信息，包含用户所在部门ID集合信息
     *
     * @param userId:用户id
     * @return UsersDto 用户信息
     * @author QcCheng Tech
     * @date 2023/7/5
     * @update 2024/8/2 原来获取用户所在部门ID集合（不分项目），现修改为只返回用户所在当前项目中的部门ID集合
     */
    public UsersDto get(int userId,List<Integer> userValidDeptIds) throws QCPromptException {
        QcUsers qcUsers = getEntity(userId);

        //获取指定用户的部门id集合
        List<Integer> deptIds = deptUserService.getUserRelatedDeptIds(userId, null);

        List<Integer> deptIdList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(deptIds)){
            //用户有效部门ID集合（当前项目的部门）与用户所属部门ID集合（可能有不同项目的部门）取交集（只取当前项目用户所属的部门ID集合）
            deptIdList = deptIds.stream().filter(userValidDeptIds::contains).collect(Collectors.toList());
        }

        if (qcUsers != null) {
            UsersDto userDto = UserMapper.MAPPER.toUserDto(qcUsers);
            userDto.setDepts(deptIdList);
            return userDto;
        }

        throw new QCPromptException("指定的用户信息不存在");
    }

    /**
     * 重置密码
     *
     * @param userId:              用户id
     * @param userDefaultPassword: 使用重置为默认密码，还是重置为随机生成密码
     * @return String 成功返回null，失败返回错误信息
     * @author QcCheng Tech
     * @date 2023/7/5
     */
    public UserResetPasswordResultDto resetPassword(int userId, boolean userDefaultPassword) {
        UserResetPasswordResultDto result = new UserResetPasswordResultDto();

        String password = PasswordUtil.DEFAULT_USER_PASSWORD;
        if (!userDefaultPassword)
            password = PasswordUtil.generateQuChengRandomPassword();

        result.setPwd(password);
        //获取加密后的密文
        String encryptPassword = PasswordUtil.getQuChengEncryptPassword(password);
        //修改用户的密码
        QcUsers qcUsers = new QcUsers();
        LambdaUpdateWrapper<QcUsers> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(QcUsers::getId, userId);
        wrapper.set(QcUsers::getPassword, encryptPassword);
        if (userDefaultPassword)
            wrapper.set(QcUsers::getPwdflag, QcUserPwdSrcTypeEnum.INIT);
        else
            wrapper.set(QcUsers::getPwdflag, QcUserPwdSrcTypeEnum.RESET);
        wrapper.set(QcUsers::getPwdtm, DateUtil.getNowDate());

        int update = repository.update(qcUsers, wrapper);
        if (update == 0x1) {
            //重置密码成功
            result.setSuccess(true);

            //密码日志记录
            QcUserPasswordLogs passwordLog = new QcUserPasswordLogs();
            passwordLog.setId(qcUsers.getId());
            passwordLog.setPassword(encryptPassword);
            passwordLog.setFlag(QcUserPwdSrcTypeEnum.RESET);
            passwordLog.setTm(DateUtil.getNowDate());
            passwordLogService.addLog(passwordLog);
        } else {
            result.setMsg("修改用户密码信息失败");
        }

        return result;
    }

    /**
     * 设置密码，用于修改指定用户ID的密码
     *
     * @param userId   用户ID
     * @param password 密码，加密后的密码
     * @return java.lang.String
     * @author QuCheng Tech
     * @since 2023/8/24
     */
    public String setPassword(int userId, String password) {
        LambdaUpdateWrapper<QcUsers> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(QcUsers::getId, userId);
        wrapper.set(QcUsers::getPassword, password);
        wrapper.set(QcUsers::getPwdflag, QcUserPwdSrcTypeEnum.USER_SET);
        wrapper.set(QcUsers::getPwdtm, DateUtil.getNowDate());

        //可以在此添加查询密码日志，判断最近几次的密码不能重复

        if (repository.update(null, wrapper) < 0x1)
            return QCUnifyReturnValue.Warn("设置用户密码失败!");

        //密码日志记录
        QcUserPasswordLogs passwordLog = new QcUserPasswordLogs();
        passwordLog.setId(userId);
        passwordLog.setPassword(password);
        passwordLog.setFlag(QcUserPwdSrcTypeEnum.USER_SET);
        passwordLog.setTm(DateUtil.getNowDate());
        passwordLogService.addLog(passwordLog);

        return QCUnifyReturnValue.Success();
    }

    /**
     * 获取用户与项目的关联信息
     *
     * @param userId 用户id
     * @return 用户与项目的关联信息
     * @throws QCPromptException
     */
    public List<UserProjectDto> getUserProjects(int userId) throws QCPromptException {
        //获取启用状态的项目集合
        List<ProjectDto> projects = projectService.getValidProjectsList(ResourceStatusFlagEnum.NORMAL);
        if (projects == null || projects.size() < 0x1)
            throw new QCPromptException("平台中不存在任何有效项目信息！");
        //用户关联的项目取交集
        List<String> userProjectCodes = userProjectService.getByUserId(userId);

        List<UserProjectDto> result = new ArrayList<>();

        for (ProjectDto projectDto : projects) {
            boolean related = false;
            if (userProjectCodes != null && userProjectCodes.size() > 0x0) {
                if (userProjectCodes.contains(projectDto.getCode())) {
                    related = true;
                }
            }
            UserProjectDto dto = new UserProjectDto();
            dto.setProject(projectDto);
            dto.setChecked(related);
            result.add(dto);
        }

        return result;
    }

    /**
     * 设置用户与项目关联关系，可一次设置多个项目
     *
     * @param dto: 关联信息
     * @return String 成功返回null，失败返回错误信息
     * @author QcCheng Tech
     * @date 2023/7/5
     */
    public String setUserProjects(UserProjectSetDto dto) {
        if (dto == null)
            return QCUnifyReturnValue.Warn("设置的信息不能为空");

        int userId = dto.getUserid();
        QcUsers en = getEntity(userId);
        if (en == null)
            return QCUnifyReturnValue.Warn("指定的用户信息错误或不存在");
        //先按用户ID删除用户与项目关联关系
        userProjectService.deleteByUserId(userId);
        //遍历目录，先删除项目的关联关系，再添加
        if (dto.getPids() != null && dto.getPids().length > 0x0) {
            for (String projectCode : dto.getPids()) {
                userProjectService.add(userId, projectCode);
            }
        }

        return QCUnifyReturnValue.Success();
    }

    /**
     * 查询用户与部门的关联关系
     *
     * @param condition:      查询条件
     * @param includeDisable: 部门状态
     * @return List<UserDeptDto> 部门信息
     * @author QcCheng Tech
     * @date 2023/7/5
     */
    public List<UserDeptDto> getUserDepts(DeptQueryConditionDto condition, boolean includeDisable) throws QCPromptException {
        if (condition == null)
            throw new QCPromptException("获取用户部门信息条件对象不能为空");
        if (condition.getId() < 0x0)
            throw new QCPromptException("获取用户部门信息条件对象用户ID不能为空");
        //由于查询用户与部门关联关系结果中需要返回的信息为项目中的所有部门集合和是否与当前用户关联
        //因此需要先根据项目编码查询出项目中的所有部门信息，再根据用户与部门关联关系确定部门是否关联勾选
        //获取项目中的所有部门
        List<DeptSimpleDto> projectAllDepts = deptService.querySimpleInfoList(condition.getProject(), includeDisable, 0x0,false);
        if (projectAllDepts == null)
            throw new QCPromptException("当前项目中无任何部门信息");
        //得到项目中的所有部门ID集合，作为筛选过滤条件传入
        List<Integer> projectAllDeptIds = projectAllDepts.stream().map(p -> p.getId()).collect(Collectors.toList());
        //获取指定用户关联的部门ID集合
        List<Integer> userRelatedDeptIds = deptUserService.getByUserId(condition.getId(), projectAllDeptIds);
        //处理结果：遍历项目中的所有部门信息，根据用户关联部门ID集合设置是否选中
        List<UserDeptDto> result = new ArrayList<>();
        for (DeptSimpleDto deptSimpleDto : projectAllDepts) {
            boolean related = false;
            if (userRelatedDeptIds != null && userRelatedDeptIds.size() > 0x0) {
                if (userRelatedDeptIds.contains(deptSimpleDto.getId())) {
                    related = true;
                }
            }
            UserDeptDto dto = new UserDeptDto();
            dto.setDept(deptSimpleDto);
            dto.setChecked(related);

            result.add(dto);
        }

        return result;
    }

    /**
     * 设置用户与部门关联关系，可一次设置多个部门
     *
     * @param dto: 用户与部门的关联信息
     * @return String 成功返回null，失败返回错误信息
     * @author QcCheng Tech
     * @date 2023/7/5
     */
    public String setUserDepts(UserDeptSetDto dto) {
        if (dto == null)
            return QCUnifyReturnValue.Warn("设置的信息不能为空");
        if (StringUtils.isBlank(dto.getProject()))
            return QCUnifyReturnValue.Warn("指定的项目编码不能为空");

        int userId = dto.getUserid();
        QcUsers en = getEntity(userId);
        if (en == null)
            return QCUnifyReturnValue.Warn("指定的用户信息错误或不存在");

        //需要先根据项目获取所有部门ID
        String projectCode = dto.getProject();
        if (!projectService.hasCodeExist(projectCode))
            return QCUnifyReturnValue.Warn("指定的项目信息错误或不存在");
        List<QcDepts> projectDepts = deptService.getProjectAllDepts(projectCode, false);
        if (projectDepts == null || projectDepts.size() < 0x1)
            return QCUnifyReturnValue.Warn("指定的项目中无任何部门信息");

        List<Integer> projectDeptIds = projectDepts.stream().map(p -> p.getId()).collect(Collectors.toList());
        //先按用户ID删除用户与部门关联关系
        //不能按用户ID删除所有与部门关联关系，可能会导致将其他项目中该用户与部门关联也一并删除
        deptUserService.deleteByUserIdAndDeptIds(userId, projectDeptIds);
        //遍历目录，先删除项目的关联关系，再添加
        if (dto.getDids() != null && dto.getDids().size() > 0x0) {
            for (int deptId : dto.getDids()) {
                deptUserService.add(userId, deptId);
            }
        }

        return QCUnifyReturnValue.Success();
    }

    /**
     * 删除用户与部门关联关系
     * 
     * @param projectCode 项目编码
     * @param userId 用户ID
     * @return 成功返回null，失败返回错误信息
     * @author QuCheng Tech
     * @since 2024/8/2
     */
    public String deleteUserDepts(String projectCode,Integer userId){
        //需要先根据项目获取所有部门ID
        if (!projectService.hasCodeExist(projectCode))
            return QCUnifyReturnValue.Warn("指定的项目信息错误或不存在");

        List<QcDepts> projectDepts = deptService.getProjectAllDepts(projectCode, false);
        if (projectDepts == null || projectDepts.size() < 0x1)
            return QCUnifyReturnValue.Warn("指定的项目中无任何部门信息");

        List<Integer> projectDeptIds = projectDepts.stream().map(p -> p.getId()).collect(Collectors.toList());

        //按用户ID删除用户与部门关联关系
        //不能按用户ID删除所有与部门关联关系，可能会导致将其他项目中该用户与部门关联也一并删除
        deptUserService.deleteByUserIdAndDeptIds(userId, projectDeptIds);
        
        return QCUnifyReturnValue.Success();
    }

    /**
     * 生成用户ID，获取数据库表中的最大记录ID+1
     *
     * @return 生成用户ID
     * @author QuCheng Tech
     * @since 2023/5/25
     */
    Integer generateId() {
        Integer maxRecordId = getMaxId();
        return maxRecordId + 1;
    }

    /**
     * 获取数据库表中的最大ID值，没有记录时返回0
     *
     * @return 返回数据库表中的最大ID值
     * @author QuCheng Tech
     * @since 2023/5/25
     */
    Integer getMaxId() {
        LambdaQueryWrapper<QcUsers> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(QcUsers::getId);
        wrapper.orderByDesc(QcUsers::getId);
        QcUsers en = repository.selectOne(wrapper);
        if (en != null) return en.getId();

        return 0x0;
    }

    /**
     * 批量导入用户
     *
     * @param dto: 文件信息
     * @return String 成功返回null，失败返回错误信息
     * @author QcCheng Tech
     * @date 2023/7/5
     */
    public String importUsers(UserImportDto dto) {
        //通过文件id获取excel路径和名称
        return null;
    }

    /**
     * 以树形结构返回结果，按部门的上下级关系列出所有部门；
     *
     * @param deptsConditionDto:条件
     * @return TreeDataDto 返回结果集
     * @author QcCheng Tech
     * @date 2023/9/8
     */
    public TreeDataDto getUserDeptsTree(UserDeptsConditionDto deptsConditionDto) throws QCPromptException {
        if (deptsConditionDto == null) {
            throw new QCPromptException("查询条件为空");
        }
        if (StringUtils.isBlank(deptsConditionDto.getProject())) {
            throw new QCPromptException("项目编码不能为空");
        }
        if (deptsConditionDto.getId() < 1) {
            throw new QCPromptException("用户ID不能为空");
        }

        //构建返回结果集
        TreeDataDto result = new TreeDataDto();


        // 通过项目编码查询项目部门集合
        List<QcDepts> projectAllDepts = deptService.getProjectAllDepts(deptsConditionDto.getProject(), false);
        if (projectAllDepts == null || projectAllDepts.isEmpty()) {
            return null;
        }
        // 通过项目部门id集合查询部门和用户的关联关系
        List<Integer> projectDeptsIds = projectAllDepts.stream()
                .map(QcDepts::getId)
                .collect(Collectors.toList());
        List<QcDeptUser> deptUserRelations = deptUserService.getEntityByDeptIds(projectDeptsIds);

        //过滤获得指定用户和项目部门的关联关系
        if (deptUserRelations != null && !deptUserRelations.isEmpty()) {
            List<QcDeptUser> filterDeptUserRelations = deptUserRelations.stream()
                    .filter(deptUser -> deptUser.getUserid().equals(deptsConditionDto.getId()))
                    .collect(Collectors.toList());

            //获得指用户关联的部门ID集合
            List<Integer> deptIds = filterDeptUserRelations.stream()
                    .map(QcDeptUser::getDeptid)
                    .collect(Collectors.toList());
            //将部门id集合添加至返回结果集中
            if (deptIds != null && !deptIds.isEmpty()) {
                List<String> checkedKeys = deptIds.stream().map(Object::toString).collect(Collectors.toList());
                result.setCheckedKeys(checkedKeys);
            }
        }

        // 获取一级部门
        List<QcDepts> level1Depts = projectAllDepts.stream()
                .filter(dept -> dept.getParentid() == null || dept.getParentid().equals(0x0))
                .collect(Collectors.toList());

        //构建部门树形结果集
        List<QCTreeNode> treeNodes = new ArrayList<>();
        for (QcDepts level1Dept : level1Depts) {
            QCTreeNode level1TreeNode = new QCTreeNode();
            level1TreeNode.setKey(String.valueOf(level1Dept.getId()));
            level1TreeNode.setTitle(level1Dept.getName());
            level1TreeNode.setLeaf(true);

            // 获取一级部门的下级部门
            List<QcDepts> level2Depts = projectAllDepts.stream()
                    .filter(dept ->dept.getParentid()!=null && dept.getParentid().equals(level1Dept.getId()))
                    .collect(Collectors.toList());

            if (!level2Depts.isEmpty()) {
                level1TreeNode.setLeaf(false);

                List<QCTreeNode> level2TreeNodes = new ArrayList<>();
                for (QcDepts level2Dept : level2Depts) {
                    QCTreeNode level2TreeNode = new QCTreeNode();
                    level2TreeNode.setKey(String.valueOf(level2Dept.getId()));
                    level2TreeNode.setTitle(level2Dept.getName());
                    level2TreeNode.setLeaf(true);
                    // 可以继续获取三级节点

                    level2TreeNodes.add(level2TreeNode);
                }

                level1TreeNode.setChildren(level2TreeNodes);
            }

            treeNodes.add(level1TreeNode);
        }

        result.setNodes(treeNodes);
        return result;
    }

    /**
     * 获取指定部门中的有效用户集合
     *
     * 获取指定部门中的有效用户集合，不包含子级部门下的用户；
     *
     * @param deptId 部门ID
     * @return List<UserInfoDto>
     * @author QuCheng Tech
     * @since 2024/11/20
     */
    public List<UserInfoDto> getDeptUsers(Integer deptId){

        //获取指定部门关联的用户ID集合
        List<Integer> deptUserIds = deptUserService.getDeptRelatedUserIds(deptId);
        if (CollectionUtils.isNotEmpty(deptUserIds)){
            //获取有效的用户信息集合
            LambdaQueryWrapper<QcUsers> wrapper = new LambdaQueryWrapper<>();
            wrapper.in(QcUsers::getId,deptUserIds)
                    .eq(QcUsers::getFlag,ResourceStatusFlagEnum.NORMAL);
            List<QcUsers> ens = repository.selectList(wrapper);
            
            if (CollectionUtils.isNotEmpty(ens)){
                List<UserInfoDto> users = UserMapper.MAPPER.toDtoList(ens);
                //查询设置每个用户关联的部门ID集合
                for (UserInfoDto user : users) {
                    List<Integer> userDeptIds = deptUserService.getUserRelatedDeptIds(user.getId(), null);
                    user.setDepts(userDeptIds);
                }
                return users;
            }
        }
        return null;
    }

    /***
     * 设置指定用户的自定义信息
     *
     * @param userId 用户ID
     * @param info 自定义信息，可以为空
     * @return boolean
     * @author QuCheng Tech
     * @since 2025/2/20
     */
    public boolean setCustomInfo(int userId, String info) {
        LambdaUpdateWrapper<QcUsers> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(QcUsers::getId, userId);
        wrapper.set(QcUsers::getCustominfo, info);

        //必须有要记录被修改才判定为成功
        return repository.update(null, wrapper) < 0x1 ? false : true;
    }
}